/**
 * @param {Object} cfg 地图常用操作对象定义
 */
function MapUtil(cfg) {
	this._init_(cfg);
}
MapUtil.prototype = {
	constructor: MapUtil,
	_init_: function (cfg) {
		if (cfg.map) {
			this.map = cfg.map;
			this.map.on('pointermove', function (evt) {
				var coordinate = evt.coordinate;

				/**
				 * 转换成度分秒，会有精度丢失
				 * @param value
				 * @returns {string}
				 */
				function formatDegree(value) {
					value = Math.abs(value);
					var v1 = Math.floor(value);//度
					var v2 = Math.floor((value - v1) * 60);//分
					var v3 = Math.round((value - v1) * 3600 % 60);//秒
					return v1 + '°' + v2 + '\'' + v3 + '"';
				};

				$("#mouselgtd").html(formatDegree(coordinate[0].toFixed(6)) + " E, ");
				$("#mouselatd").html(formatDegree(coordinate[1].toFixed(6)) + " N");

			});
		}
		if (cfg.view) {
			this.view = cfg.view;
		}
		if (cfg.target) {
			this.target = cfg.target;
		}
		if (cfg.mapCfg) {
			this.mapCfg = cfg.mapCfg;
		}
		this.sketch;
		this.measureTooltipElement;
		this.measureTooltip;
		this.draw; // global so we can remove it later
		this.layer_swipe = 0 //卷帘初始化
		this.prerenderListenerArr = {}
    this.init4490()

		/**
		 * Format length output.
		 * @param {module:ol/geom/LineString~LineString} line The line.
		 * @return {string} The formatted length.
		 */
		this.formatLength = function (line) {
			var sourceProj = this.map.getView().getProjection(); //获取投影坐标系
			var length = ol.sphere.getLength(line, {
				projection: sourceProj
			});
			var output;
			if (length > 100) {
				output = (Math.round(length / 1000 * 100) / 100) +
					' ' + 'km';
			} else {
				output = (Math.round(length * 100) / 100) +
					' ' + 'm';
			}
			return output;
		};

		/**
		 * Format area output.
		 * @param {module:ol/geom/Polygon~Polygon} polygon The polygon.
		 * @return {string} Formatted area.
		 */
		this.formatArea = function (polygon) {
			var sourceProj = this.map.getView().getProjection(); //获取投影坐标系
			var area = ol.sphere.getArea(polygon, {
				projection: sourceProj
			});
			var output;
			if (area > 10000) {
				output = (Math.round(area / 1000000 * 100) / 100) +
					' ' + 'km<sup>2</sup>';
			} else {
				output = (Math.round(area * 100) / 100) +
					' ' + 'm<sup>2</sup>';
			}
			return output;
		};
	},
  init4490: function () {
    proj4.defs("EPSG:4490", "+proj=longlat +ellps=GRS80 +no_defs +type=crs");
		//4490的坐标系注册进openlayer的projection中
		ol.proj.proj4.register(proj4)
		//重写projection4490，地图投影
  },
	addInteraction: function (type) {
		var this_mapUtil = this;
		this_mapUtil.draw = new ol.interaction.Draw({
			source: this_mapUtil.getLayer("celianglayer").getSource(),
			type: type,
			style: new ol.style.Style({
				fill: new ol.style.Fill({
					color: 'rgba(0, 0, 0, 0.2)'
				}),
				stroke: new ol.style.Stroke({
					color: 'rgba(255, 52, 30, 1)',
					lineDash: [5, 5],
					width: 2
				}),
				image: new ol.style.Circle({
					radius: 5,
					stroke: new ol.style.Stroke({
						color: 'rgba(255, 0, 0, 1)'
					}),
					fill: new ol.style.Fill({
						color: 'rgba(51, 255, 255, 0.4)'
					})
				})
			})
		});
	},
  getLength(line,unit='km') {
    var sourceProj = this.map.getView().getProjection(); //获取投影坐标系
    var length = ol.sphere.getLength(line, {
      projection: sourceProj
    });
    var output;
    if (unit === 'km') {
      output = (Math.round(length / 1000 * 100) / 100)
    } else {
      output = (Math.round(length * 100) / 100)
    }
    return output.toFixed(2);
  },
	getArea: function (polygon) {
		var this_mapUtil = this;
		var sourceProj = this_mapUtil.map.getView().getProjection(); //获取投影坐标系

		var area = ol.sphere.getArea(polygon, {
			projection: sourceProj
		});
		var output = area;
		return output;
	},
	getAreaByKm: function (polygon) {
		var this_mapUtil = this;
		var sourceProj = this_mapUtil.map.getView().getProjection(); //获取投影坐标系
		var area = ol.sphere.getArea(polygon, {
			projection: sourceProj
		});
		var output = area / 1000000;
		return output;
	},
	getAreaByHm: function (polygon) {
		var this_mapUtil = this;
		var sourceProj = this_mapUtil.map.getView().getProjection(); //获取投影坐标系
		var area = ol.sphere.getArea(polygon, {
			projection: sourceProj
		});
		var output = area / 10000;
		return output;
	},
	removeLayer: function (ids) {
		var arr = ids.split(",");
		var $this = this;
		var cmmaparr = [];
		$this.map.getLayers().forEach(function (layer) {
			if (layer != null && arr.includes(layer.get("bklayerId"))) {
				cmmaparr.push(layer);
			}
		});
		for (var i = 0; i < cmmaparr.length; i++) {
			$this.map.removeLayer(cmmaparr[i]);
		}
	},
	getAreaByGeoJson: function (geojson, flag) {
		var this_mapUtil = this;
		var sourceProj = this_mapUtil.map.getView().getProjection(); //获取投影坐标系
		var geoObj = new ol.format.GeoJSON();
		var f = geoObj.readFeature(geojson);

		var area = ol.sphere.getArea(f.getGeometry(), {
			projection: sourceProj
		});
		var output = area;
		if (!flag) {
			output = area / 1000000;
		}
		return output;
	},
	/**
	 * Creates a new measure tooltip
	 */
	guid: function () {
		return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
			var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
			return v.toString(16);
		});
	},
	createMeasureTooltip: function (mapUtil, id) {
		this.measureTooltip = new ol.Overlay.Popup({
			popupClass: "tips", //"tooltips", "warning" "black" "default", "tips", "shadow",
			closeBox: true,
			onshow: function () {
				console.log("You opened the box");
			},
			onclose: function () {
				if (mapUtil) {
					mapUtil.clearCeLiang(mapUtil, id);
				}
			},
			positioning: 'auto',
			autoPan: true,
			autoPanAnimation: { duration: 250 }
		});

		this.map.addOverlay(this.measureTooltip);
	},
	ceju: function () {
		var this_mapUtil = this;
		var type = "LineString";
    this_mapUtil.measureTooltip && this_mapUtil.measureTooltip.hide()
		this_mapUtil.map.removeInteraction(this_mapUtil.draw);
		this_mapUtil.celiang(type);
	},
	cemian: function () {
		var this_mapUtil = this;
		var type = "Polygon";
    this_mapUtil.measureTooltip && this_mapUtil.measureTooltip.hide()
		this_mapUtil.map.removeInteraction(this_mapUtil.draw);
		this_mapUtil.celiang(type);
	},
	celiang: function (type) {

		var this_mapUtil = this;
		this_mapUtil.addInteraction(type);
		this_mapUtil.map.addInteraction(this_mapUtil.draw);
		var listener;
		var featureid = this_mapUtil.guid();
		this_mapUtil.createMeasureTooltip(this_mapUtil, featureid);

		this_mapUtil.draw.on('drawstart',
			function (evt) {
				this_mapUtil.sketch = evt.feature;
				var tooltipCoord = evt.coordinate;
				listener = this_mapUtil.sketch.getGeometry().on('change', function (evt) {
					var geom = evt.target;
					var htmlstrs;
					if (geom instanceof ol.geom.Polygon) {
						var output = this_mapUtil.formatArea(geom);
						var output1 = this_mapUtil.formatLength(geom);
						htmlstrs = "面积：" + output + "</br>" + "周长：" + output1;
						tooltipCoord = geom.getInteriorPoint().getCoordinates();
					} else if (geom instanceof ol.geom.LineString) {
						htmlstrs = this_mapUtil.formatLength(geom);
						tooltipCoord = geom.getLastCoordinate();
					}
					this_mapUtil.measureTooltip.show(tooltipCoord, htmlstrs);

				});
			}, this);

		this_mapUtil.draw.on('drawend',
			function () {
				this_mapUtil.sketch = null;
				this_mapUtil.map.removeInteraction(this_mapUtil.draw);
				ol.Observable.unByKey(listener);
				this_mapUtil.addCeliangId(this_mapUtil, featureid);
				this_mapUtil.createMeasureTooltip(this_mapUtil, featureid);

				featureid = null;
			}, this);
	},
	addCeliangId: function (this_mapUtil, featureid) {
		setTimeout(function () {
			var featureArrays = this_mapUtil.getLayer("celianglayer").getSource().getFeatures();
			for (var i = 0; i < featureArrays.length; i++) {
				if (featureArrays[i].id == null || featureArrays[i].id == undefined) {
					featureArrays[i].id = featureid;
				}
			}
		}, 200)
	},
	clearCeLiang: function (mapUtil, featureid) {
		var Element = $("#" + featureid);
		if (Element) {
			Element.parent().remove();
		}
		var source = mapUtil.getLayer("celianglayer").getSource();
		var featureArrays = source.getFeatures();
		for (var i = 0; i < featureArrays.length; i++) {
			var feature = featureArrays[i];
			if (feature.id == featureid) {
				source.removeFeature(feature)
			}
		}
	},
	getLayer: function (id) {
		var ly = null;
		this.map.getLayers().forEach(function (layer) {
			if (layer&&layer.get("bklayerId") == id) {
				ly = layer;
				return false;
			}
		});
		return ly;
	},
	getCurrentExtent: function () {
		return this.view.calculateExtent();
	},
	//地图平移
	panDirection: function (direction, zoom) {
		var this_mapUtil = this;
		var lonlat = 0.005;//平移
		var mapCenter = this.view.getCenter();
		console.log("zoom" + zoom);
		console.log("mapCenter" + mapCenter);

		switch (direction) {
			case "north":
				mapCenter[1] += lonlat;
				break;
			case "south":
				mapCenter[1] -= lonlat;
				break;
			case "west":
				mapCenter[0] -= lonlat
				break;
			case "east":
				mapCenter[0] += lonlat;
				break;
		}
		console.log("mapCenter" + mapCenter);
		//更改center 实现地图平移
		this.view.setCenter(mapCenter);
		//对地图进行渲染
		this_mapUtil.map.render();
	},

	mapFull: function (param) {
		var default_params = {
			padding: [10, 10, 10, 10],
			duration: 500
		}
		if (param) {
			default_params = param;
		} else if (param == "noAnimation") {
			default_params = {
				padding: [10, 10, 10, 10]
			}
		}
		this.view.fit([this.mapCfg.GlobalCfg.extend.xmin, this.mapCfg.GlobalCfg.extend.ymin, this.mapCfg.GlobalCfg.extend.xmax, this.mapCfg.GlobalCfg.extend.ymax], default_params);
	},
	mapFullByextend: function (extend, param) {
		var default_params = {
			padding: [10, 10, 10, 10],
			duration: 500
		}
		if (param != null && param != undefined && typeof (param) == "object") {
			default_params = param;
		} else if (param == "noAnimation") {
			default_params = {
				padding: [10, 10, 10, 10]
			}
		}
		this.view.fit(extend, default_params);
	},
	/**
		* 创建圈画draw
		* @param layerId
		* @param drawType
		* @param eventConfig
		* @param extra
		* @returns {ol.interaction.Draw}
		*/
	createDraw: function (layerId, drawType, eventConfig, extra) {
		var $this = this;
		var option = {
			source: this.getLayer(layerId).getSource(),
			type: drawType,
			style: styleFunction
		};
		if (drawType == "Rectangle") {
			option = {
				source: this.getLayer(layerId).getSource(),
				geometryFunction: ol.interaction.Draw.createBox(),
				type: "Circle",
				style: styleFunction
			};
		} else if (drawType === 'Circle') {
      option = {
        source: this.getLayer(layerId).getSource(),
        type: 'Circle',
        style: styleFunction2
      }
    }
    function styleFunction2(feature) {
			var styles = new ol.style.Style({
				geometry: feature.getGeometry(),
				stroke: new ol.style.Stroke({
					color: "#ff0000",
					width: 2
				}), image: new ol.style.Circle({
					radius: 4,
					fill: new ol.style.Fill({
						color: '#ffffff'
					}),
					stroke: new ol.style.Stroke({
						color: '#ff0000',
						width: 2
					})
				})
			});
			return styles;
		}
		function styleFunction(feature) {
			var styles = [];
			styles.push(new ol.style.Style({
				stroke: new ol.style.Stroke({
					color: "#ff0000",
					width: 2
				}), image: new ol.style.Circle({
					radius: 4,
					fill: new ol.style.Fill({
						color: '#ffffff'
					}),
					stroke: new ol.style.Stroke({
						color: '#ff0000',
						width: 2
					})
				})
			}))
			styles.push(
				new ol.style.Style({
					geometry: function (feature) {
						var coordinates = feature.getGeometry().getCoordinates();
						return new ol.geom.MultiPoint(coordinates);
					}, image: new ol.style.Circle({
						radius: 4,
						fill: new ol.style.Fill({
							color: '#ffffff'
						}),
						stroke: new ol.style.Stroke({
							color: '#ff0000',
							width: 2
						})
					})
				})
			);
			return styles;
		}
		if (!this.isNull(extra)) $.extend(option, extra);
		// this.createDraw = new ol.interaction.Draw(option);
		var createDraw = new ol.interaction.Draw(option);
		if (eventConfig) {
			for (var eventName in eventConfig) {
				createDraw.on(eventName, eventConfig[eventName]);
			}
		}
		this.map.addInteraction(createDraw);
		return createDraw;
	},
	/**
  * 创建撤销
  * @param options { layers: Array, maxLength: number}
  * @returns {ol.interaction.UndoRedo}
  */
  createUndoRedo: function(options){
    const undoredo = new ol.interaction.UndoRedo(options);
    this.map.addInteraction(undoredo);
    return undoredo;
  },
	/**
	* 创建编辑modify
	* @param layerId
	* @param eventConfig
	* @param extra
	* @returns {ol.interaction.Modify}
	*/
	createModify: function (layerId, eventConfig, extra) {
		var option = {
			title: '移除该点',
			source: this.getLayer(layerId).getSource()
		};

		if (!this.isNull(extra)) $.extend(option, extra);

		this.modify = new ol.interaction.ModifyTouch(option);

		if (eventConfig) {
			for (var eventName in eventConfig) {
				this.modify.on(eventName, eventConfig[eventName]);
			}
		}

		this.map.addInteraction(this.modify);

		return this.modify;
	},
	/**
	 *
	 * @param {图层id} id
	 * @param {查询坐标点} coordinate
	 * @returns 图形要素
	 */
	getGeoServerLayerInfo: function (id, coordinate) {
		var layer = this.getLayer(id);
		if (layer == null || !layer.getVisible()) {
			return null;
		}
		var url = layer.getSource().getFeatureInfoUrl(coordinate, this.view.getResolution(), this.view.getProjection(), { 'INFO_FORMAT': 'application/json', 'FEATURE_COUNT': 50 });

		if (url) {
			return this.getSyncJson(url, {}, 120000);
		} else {
			console.log(layer.get("bklayerName") + "获取查询url失败");
			return null;
		}
	},
	/**
	 *
	 * @param {请求地址} url
	 * @param {参数} data
	 * @param {超时时间} timeout
	 * @returns
	 */
	getSyncJson: function (url, data, timeout) {
		var responseArray = {};
		try {
			$.ajax({
				url: url,
				type: 'POST',
				timeout: timeout || 30000,
				async: false,
				data: data,
				dataType: 'json',
				cache: false,
				success: function (data) {
					responseArray = data;
				},
				error: function (XMLHttpRequest, textStatus, errorThrown) {
					console.error("地图查询服务错误！");
				}
			});
		}
		catch (e) {
			console.error("地图服务异常！");
		}
		return responseArray;
	},
	changerKeyUppe: function (jsonObj) {
		for (var key in jsonObj) {
			jsonObj[key.toUpperCase()] = jsonObj[key];
			delete (jsonObj[key]);
		}
		return jsonObj;
	},
	/**
	 * 创建捕获snap
	 * @param cmMap
	 * @param mapUtil
	 * @param layerId
	 */
	createSnap: function (layerId, extra) {
		var option = {
			source: this.getLayer(layerId).getSource()
		};

		if (!this.isNull(extra)) $.extend(option, extra);

		var snap = new ol.interaction.Snap(option);

		this.map.addInteraction(snap);

		return snap;
	},
	/**
	 *
	 * @param {图形元素集合} features
	 * @param {图标路径字段} gificon
	 */
	setGifLayer(features, gificon) {
		var this_mapUtil = this
		features.forEach((feature) => {
			var gifUrl = feature.getProperties()[gificon]
			var gif = gifler(gifUrl)
			gif.frames(
				document.createElement('canvas'),
				function (ctx, frame) {
					if (!feature.getStyle()) {
						feature.setStyle(
							new ol.style.Style({
								image: new ol.style.Icon({
									img: ctx.canvas,
									imgSize: [frame.width, frame.height],
									opacity: 0.8,
								}),
							})
						)
					}
					ctx.clearRect(0, 0, frame.width, frame.height)
					ctx.drawImage(frame.buffer, frame.x, frame.y)
					this_mapUtil.map.render()
				},
				true
			)
		})
	},
	/**
	 * 地图事件
	 * @param {图层ids} layerId
	 * @param {事件类型 } eventType
	 * @param {选中样式 } style
	 * @returns 图形要素
	 */
	 createMapEvent: function (layerIds, eventType, style, filter) {
     const finalFilter = filter ? filter :  function (feature, layer) {
      return layer != null && layerIds.indexOf(layer.get('bklayerId')) > -1
    }
		// if (!style) {
		// 	style = new ol.style.Style({
		// 		fill: new ol.style.Fill({
		// 			color: '#eeeeee'
		// 		}),
		// 		stroke: new ol.style.Stroke({
		// 			color: 'rgba(255, 255, 255, 0.7)',
		// 			width: 2
		// 		})
		// 	})
		// }
		let select = null;
		if (eventType == 'singleclick') {
			select = new ol.interaction.Select({
				style: style,
				filter: finalFilter
			});
		} else if (eventType == 'pointermove') {
			select = new ol.interaction.Select({
				condition: ol.events.condition.pointerMove,
				style: style,
				filter: finalFilter
			});
		} else if (eventType == 'altclick') {
			select = new ol.interaction.Select({
				condition: function (mapBrowserEvent) {
					return ol.events.condition.click(mapBrowserEvent) && ol.events.condition.platformModifierKeyOnly(mapBrowserEvent);
				},
				style: style,
				filter: finalFilter
			});
		} else {
			select = new ol.interaction.Select({
				style: style,
				filter: finalFilter
			});
		}
		this.map.addInteraction(select);
		return select;
	},
	/**
	 * 创建透视
	 */
	createClip: function () {
		this.clip = new ol.interaction.Clip({ radius: 80 });
		this.map.addInteraction(this.clip);
		this.clip.setActive(false);

	},
	/**
	 * 开启透视
	 * @param {图层id} layerId
	 * @param {半径} radius
	 */
	startClip: function (layerId, radius) {
		if (this.clip) {
			this.clip.setRadius(radius || 80)
			this.clip.setActive(true)
			this.clip.removeLayers()
			var layer = this.getLayer(layerId)
			if (layer) {
				layer.setZIndex(1000);
				layer.setVisible(true)
				this.clip.addLayer(layer)
			}
		}
	},
	/**
 * 关闭透视
 * @param {图层id} layerId
 */
	stopClip: function (layerId) {
		if (this.clip) {
			this.clip.setActive(false);
			this.clip.removeLayers()
			var layer = this.getLayer(layerId)
			if (layer != null) {
				layer.setVisible(false)
				layer.setZIndex(layer.get("bklayerSn"));
			}
		}
	},
	/**
	 * 变更影像图
	 * 只显示分组中id，其他隐藏
	 * @param {图层id} id
	 * @param {分组id} type
	 */
	changeYxMap: function (id, type) {
		this.map.getLayers().forEach(function (layer) {
			if (layer&&layer.get("bklayerGroupId") == type) {
				layer.setVisible(false)
			}
			if (layer&&layer.get("bklayerGroupId") == type) {
				if (layer.get("bklayerId") == id) {
					layer.setVisible(true);
				} else {
					layer.setVisible(false);
				}
			}
		})
	},
	/**
 * 显示与隐藏图层
 * 只显示分组中id，其他隐藏
 * @param {图层layerId} layerId
 * @param {true false} visible
 */
	changeLayer: function (layerId, visible) {
		const layer = this.getLayer(layerId)
		if (layer) {
			layer.setVisible(visible)
		}
	},
	/****************************************************  样式相关  *************************************************************/

	/**
	 * 获取点style
	 * @param color
	 * @param fillcolor
	 * @param radius
	 * @param width
	 * @param extra
	 * @returns {ol.style.Style}
	 */
	getPointStyle: function (color, fillcolor, radius, width, extra) {
		var option = {};

		if (this.isNull(radius)) radius = 5;
		if (this.isNull(color)) color = [255, 204, 102, 1];
		if (this.isNull(fillcolor)) fillcolor = [255, 204, 102, 0.8];
		if (this.isNull(width)) width = 1;

		var circle = new ol.style.Circle({
			radius: radius,
			stroke: new ol.style.Stroke({
				color: color,
				width: width
			}),
			fill: new ol.style.Fill({
				color: fillcolor
			})
		})

		$.extend(option, { image: circle });

		if (!this.isNull(extra)) $.extend(option, extra);

		return new ol.style.Style(option);
	},
	getPointStyleFontSymbol: function (glyph, fillcolor, radius, width, extra) {
		var option = {};
		return new ol.style.Style({
			image: new ol.style.FontSymbol({
				form: "bubble", //"hexagone",
				gradient: false,
				glyph: "fa-question",//car[Math.floor(Math.random()*car.length)],
				fontSize: 1,
				fontStyle: "",
				radius: 15,
				//offsetX: -15,
				rotation: 0 * Math.PI / 180,
				rotateWithView: false,
				offsetY: 0,
				color: "black",
				fill: new ol.style.Fill({
					color: "white"
				}),
				stroke: new ol.style.Stroke({
					color: "white",
					width: 4
				})
			}),
			stroke: new ol.style.Stroke({
				width: 2,
				color: '#f80'
			}),
			fill: new ol.style.Fill({
				color: [255, 136, 0, 0.6]
			})
		});
	},
	/**
	 * 获取点ImgStyle
	 * @param url
	 * @param scale
	 * @param opacity
	 * @param extra
	 * @returns {ol.style.Style}
	 */
	getPointImgStyle: function (url, scale, opacity, extra) {

		if (this.isNull(opacity)) opacity = 1;
		if (this.isNull(scale)) scale = 0.45;

		var iconOption = new ol.style.Icon({
			offset: [0, 0],
			opacity: opacity,
			scale: scale,
			src: url
		});
		var option =  { image: iconOption };

		if (!this.isNull(extra)) $.extend(option, extra);

		return new ol.style.Style(option);
	},
	/**
	 * 获取线style
	 * @param color
	 * @param width
	 * @param extra
	 * @returns {ol.style.Style}
	 */
	getLineStyle: function (color, width, extra) {
		if (this.isNull(color)) color = [255, 204, 102, 1];
		if (this.isNull(width)) width = 1;

		var option = {
			stroke: new ol.style.Stroke({
				color: color,
				width: width
			})
		}


		if (!this.isNull(extra)) $.extend(option, extra);

		return new ol.style.Style(option);
	},
	/**
	 * 获取面style
	 * @param lineColor
	 * @param lineWidth
	 * @param fillColor
	 * @param extra
	 * @returns {ol.style.Style}
	 */
	getPolygonStyle: function (lineColor, lineWidth, fillColor, extra, strokeExt, fillExt) {
		if (this.isNull(lineColor)) lineColor = [255, 204, 102, 1];
		if (this.isNull(lineWidth)) lineWidth = 1;
		if (this.isNull(fillColor)) fillColor = [55, 114, 2, 0.05];

		var strokeOpt = {
			color: lineColor,
			width: lineWidth
		}
		if (!this.isNull(strokeExt)) $.extend(strokeOpt, strokeExt);

		var fillOpt = {
			color: fillColor
		}
		if (!this.isNull(fillExt)) $.extend(fillOpt, fillExt);

		var option = {
			stroke: new ol.style.Stroke(strokeOpt),
			fill: new ol.style.Fill(fillOpt)
		}

		if (!this.isNull(extra)) $.extend(option, extra);

		return new ol.style.Style(option);
	},
	getPointEditStyle: function () {
		return [
			new ol.style.Style({
				image: new ol.style.Circle({
					radius: 4,
					fill: new ol.style.Fill({
						color: '#ffffff'
					}),
					stroke: new ol.style.Stroke({ color: '#ff0000', width: 2 })
				}),
				geometry: function (feature) {
					var coordinates;
					if (feature.getGeometry().getType() == "LineString") {
						coordinates = feature.getGeometry().getCoordinates();
					} else if (feature.getGeometry().getType() == "Polygon") {
						coordinates = feature.getGeometry().getCoordinates()[0];
					} else if (feature.getGeometry().getType() == "MultiLineString") {
						coordinates = feature.getGeometry().getCoordinates()[0];
					} else if (feature.getGeometry().getType() == "MultiPoint") {
						coordinates = feature.getGeometry().getCoordinates();
					} else if (feature.getGeometry().getType() == "Point") {
						//not 100% sure this would work!!!!
						coordinates = [feature.getGeometry().getCoordinates()];
					} else if (feature.getGeometry().getType() == "Circle") {
						return "";
					} else if (feature.getGeometry().getType() == "MultiPolygon") {
						var cds = feature.getGeometry().getCoordinates();
						var cds_arr = [];
						for (var i = 0; i < cds.length; i++) {
							var p = cds[i];
							for (var n = 0; n < p.length; n++) {
								var np = p[n];
								for (var t = 0; t < np.length; t++) {
									cds_arr.push(np[t]);
								}
							}
						}
						return new ol.geom.MultiPoint(cds_arr);
					} else {
						console.log('maybe you need to handle also multi geometries!', '', '确定', function (e) { }, 'div')
					}
					return new ol.geom.MultiPoint(coordinates);
				}
			}),
			new ol.style.Style({
				stroke: new ol.style.Stroke({
					color: "#ff0000",
					width: 2
				}),
				fill: new ol.style.Fill({
					color: "rgba(255,255,255,0.1)"
				})
			})
		]
	},
	/****************************************************  工具函数 *************************************************************/
	getTileRangeForExtentAndZ: function (extent, z, origin, resolution) {
		var xmin_ymin = this.getTileCoordForXYAndZ_(extent[0], extent[3], z, false, origin, resolution);
		var xmax_ymax = this.getTileCoordForXYAndZ_(extent[2], extent[1], z, true, origin, resolution);
		return [xmin_ymin[0], xmin_ymin[1], xmax_ymax[0], xmax_ymax[1]];
	},
	getTileCoordForXYAndZ_: function (x, y, z, b, origin, resolution) {
		var tileSize = [256, 256];
		var adjustX = b ? 0.5 : 0;
		var adjustY = b ? 0.5 : 0;
		var xFromOrigin = Math.floor((x - origin[0]) / resolution + adjustX);
		var yFromOrigin = Math.floor((origin[1] - y) / resolution + adjustY);
		var tileCoordX = xFromOrigin / tileSize[0];
		var tileCoordY = yFromOrigin / tileSize[1];
		if (b) {
			tileCoordX = Math.ceil(tileCoordX) - 1;
			tileCoordY = Math.ceil(tileCoordY) - 1;
		}
		else {
			tileCoordX = Math.floor(tileCoordX);
			tileCoordY = Math.floor(tileCoordY);
		}
		return [tileCoordX, tileCoordY];
	},
	/**
	 * 判断是否为空
	 * @param value
	 * @returns {boolean}
	 */
	isNull: function (value) {
		if (typeof value == "undefined") {
			return true;
		} else if (typeof value == "string") {
			if (value == "") return true;
			else return false;
		} else if (typeof value == "object") {
			if (value == null || $.isEmptyObject(value)) return true;
			else return false;
		} else {
			return false;
		}
	},


	/**
	 * 经纬度转换--度转度分秒
	 * @param value
	 * @returns {string}
	 */
	formatDegree: function (value) {
		value = Math.abs(value);
		var v1 = Math.floor(value);//度
		var v2 = Math.floor((value - v1) * 60);//分
		var v3 = Math.round((value - v1) * 3600 % 60);//秒
		return v1 + '°' + v2 + '′' + v3 + '″';
	},

	/**
	 * 经纬度转换--度分秒转度
	 * @param value
	 * @constructor
	 */
	DegreeConvertBack: function (value) {
		var du = value.split("°")[0];
		var fen = value.split("°")[1].split("′")[0];
		var miao = value.split("°")[1].split("′")[1].split('″')[0];
		return Math.abs(du) + (Math.abs(fen) / 60 + Math.abs(miao) / 3600);
	},

	/**
	 * 对象数组按照某一属性进行排序
	 * @param arr
	 * @param meta
	 * @param desc
	 * @returns {*}
	 */
	objArrSort: function (arr, meta, desc) {
		var compare = function (prop) {
			return function (obj1, obj2) {
				var val1 = obj1[prop];
				var val2 = obj2[prop];
				if (!isNaN(Number(val1)) && !isNaN(Number(val2))) {
					val1 = Number(val1);
					val2 = Number(val2);
				}
				if (val1 < val2) {
					return desc ? 1 : -1;
				} else if (val1 > val2) {
					return desc ? -1 : 1;
				} else {
					return 0;
				}
			}
		}
		return arr.sort(compare(meta));
	},
	addCkyxLayer(layer,layerId) {
		const th = this
		const prerenderListener = layer.on('prerender', function (event) {
			const ctx = event.context
			const mapSize = th.map.getSize()
			const width = mapSize[0] * (th.layer_swipe)
			const tl = ol.render.getRenderPixel(event, [width, 0])
			const tr = ol.render.getRenderPixel(event, [mapSize[0], 0])
			const bl = ol.render.getRenderPixel(event, [width, mapSize[1]])
			const br = ol.render.getRenderPixel(event, mapSize)

			ctx.save()
			ctx.beginPath()
			ctx.moveTo(tl[0], tl[1])
			ctx.lineTo(bl[0], bl[1])
			ctx.lineTo(br[0], br[1])
			ctx.lineTo(tr[0], tr[1])
			ctx.closePath()
			ctx.clip()
		})
		this.prerenderListenerArr[layerId] = prerenderListener;
		this.postrenderListener = layer.on('postrender', function (event) {
			const ctx = event.context
			ctx.restore()
		})
	},
  onPointerMove(layerIds) {
		const layerIdArr = layerIds.split(",")
		const t = this
		for (let index = 0; index < layerIdArr.length; index++) {
			const layerId = layerIdArr[index];
			var layer = t.getLayer(layerId)
			if (layer != null) {
				layer.setZIndex(1000 + index)
				layer.setVisible(true)
				t.addCkyxLayer(layer, layerId)
			}
		}
		this.pointerMoveListener = this.map.on('pointermove', function (evt) {
			var width = evt.pixel[0]
			var swidth = t.target.offsetWidth
			t.layer_swipe = width / swidth
			t.map.render()
		})
	},
  unPointerMove(layerIds) {
		const layerIdArr = layerIds.split(",")
		for (let index = 0; index < layerIdArr.length; index++) {
			const layerId = layerIdArr[index];
			var layer = this.getLayer(layerId)
			if (layer != null) {
				layer.setVisible(false)
				layer.setZIndex(layer.get("bklayerSn"));
			}
		}
		const t = this
		this.layer_swipe = 0
		this.map.render()
		if (this.pointerMoveListener) {
			ol.Observable.unByKey(this.pointerMoveListener)
		}
		if (Object.keys(this.prerenderListenerArr).length != 0) {
			for (const key in this.prerenderListenerArr) {
				if (Object.hasOwnProperty.call(this.prerenderListenerArr, key)) {
					const prerenderListener = this.prerenderListenerArr[key];
					ol.Observable.unByKey(prerenderListener)

				}
			}
			this.prerenderListenerArr = {};
		}
		if (this.postrenderListener) {
			ol.Observable.unByKey(this.postrenderListener)
		}
	},
  distance(x1, y1, x2, y2) {
    return ol.sphere.getDistance([x1, y1], [x2, y2])
  },
  getPoint3857(x, y){
    return ol.proj.transform([x, y], 'EPSG:4326', 'EPSG:3857')
  },
}
